package com.yerbamateprimer.action.user.impl;

import java.io.Serializable;

import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import com.google.common.base.Preconditions;
import com.yerbamateprimer.action.user.AsynchronousUserAction;
import com.yerbamateprimer.advice.impl.InvitationAcceptedAdvice;
import com.yerbamateprimer.model.User;
import com.yerbamateprimer.round.Round;
import com.yerbamateprimer.service.ClientService;
import com.yerbamateprimer.service.RoundService;

/**
 * This action is useful to accept
 * an invitation to the round.
 * 
 * @author Matias Liwski
 * @version 1.0
 */
public class AcceptInvitationUserAction implements AsynchronousUserAction, Serializable {
	private static final long serialVersionUID = 7819431154199246466L;
	private User user;
	private transient RoundService roundService;
	private transient ClientService clientService;

	/**
	 * Default constructor, used by the serializer.
	 */
	public AcceptInvitationUserAction() {
	}

	/**
	 * @param userId The id of the user that want to execute this action.
	 */
	public AcceptInvitationUserAction(User user) {
		this.setUser(user);
	}

	/* (non-Javadoc)
	 * @see com.yerbamateprimer.action.user.UserAction#execute()
	 */
	@Override
	public void execute() {
		checkArgumentPreconditions();
		Round round = this.roundService.getRoundForUser(this.user);
		Preconditions.checkState(round != null, "The user: " + user + " isn't invited to any round.");
		Preconditions.checkState(round.getInvitedUsers().contains(this.user), "The user: " + this.user + " is already participating in the round: " + round + ".");
		
		round.confirmUser(this.user);
		this.clientService.send(new InvitationAcceptedAdvice(round.getPrimer(), this.user));
	}

	/**
	 * Check the preconditions of the arguments needed to execute this action.
	 */
	private void checkArgumentPreconditions() {
		Preconditions.checkArgument(this.user != null, "This action need a user to execute it.");
		Preconditions.checkArgument(this.roundService != null, "This action need a round service to execute it.");
		Preconditions.checkArgument(this.clientService != null, "This action needs a client service to execute it.");
	}

	/* (non-Javadoc)
	 * @see com.yerbamateprimer.action.user.UserAction#setUser(com.yerbamateprimer.model.User)
	 */
	@Override
	public void setUser(User user) {
		Preconditions.checkArgument(user != null, "This action needs a user to execute it.");
		this.user = user;
	}

	/* (non-Javadoc)
	 * @see com.yerbamateprimer.action.user.UserAction#getUser()
	 */
	@Override
	public User getUser() {
		return this.user;
	}

	/**
	 * @param roundService The round service of the Action, to set.
	 */
	public void setRoundService(RoundService roundService) {
		Preconditions.checkArgument(roundService != null, "This action needs a round service to execute it.");
		this.roundService = roundService;
	}

	/**
	 * @return The roundService of the Action.
	 */
	public RoundService getRoundService() {
		return this.roundService;
	}

	/**
	 * @param clientService The client service of the Action, to set.
	 */
	public void setClientService(ClientService clientService) {
		Preconditions.checkArgument(clientService != null, "This action needs a client service to execute it.");
		this.clientService = clientService;
	}

	/**
	 * @return The client service of the Action.
	 */
	public ClientService getClientService() {
		return this.clientService;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE, false, true);
	}
}